package com.fjh.springboot_01.service.impl;

import com.fjh.springboot_01.mapper.LessonMapper;
import com.fjh.springboot_01.pojo.lesson.Lesson;
import com.fjh.springboot_01.service.RecommendService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class RecommendServiceImpl implements RecommendService {

    @Autowired
    private LessonMapper lessonMapper;

    @Override
    public List<Lesson> getRecommendedLessons(Integer userId, int limit) {
        // 1. 获取所有用户的行为数据（点赞和收藏，并区分行为类型）
        Map<Integer, Map<Integer, Integer>> userRatings = getUserRatings();
        
        // 2. 如果是新用户，返回热门课程
        if (!userRatings.containsKey(userId)) {
            return lessonMapper.getPopularLessons(limit);
        }

        // 3. 计算用户相似度
        Map<Integer, Double> userSimilarities = calculateUserSimilarities(userId, userRatings);
        
        // 4. 使用加权评分公式计算课程推荐得分
        Map<Integer, Double> courseScores = calculateCourseScores(userId, userRatings, userSimilarities);
        
        // 5. 获取推荐课程详细信息
        if (courseScores.isEmpty()) {
            return lessonMapper.getPopularLessons(limit);
        }
        
        // 根据得分排序并获取前limit个课程
        List<Integer> recommendedLessonIds = courseScores.entrySet().stream()
            .sorted(Map.Entry.<Integer, Double>comparingByValue().reversed())
            .limit(limit)
            .map(Map.Entry::getKey)
            .collect(Collectors.toList());

        return lessonMapper.getLessonsByIds(recommendedLessonIds);
    }

    /**
     * 获取所有用户的评分数据 
     * 点赞=1，收藏=2，两者都有=3
     */
    private Map<Integer, Map<Integer, Integer>> getUserRatings() {
        Map<Integer, Map<Integer, Integer>> ratings = new HashMap<>();
        
        // 获取所有用户的点赞和收藏数据
        List<Map<String, Object>> likes = lessonMapper.getAllLikes();
        List<Map<String, Object>> favorites = lessonMapper.getAllFavorites();

        // 处理点赞数据 (评分=1)
        likes.forEach(like -> {
            Integer userId = (Integer) like.get("userId");
            Integer lessonId = (Integer) like.get("lessonId");
            ratings.computeIfAbsent(userId, k -> new HashMap<>()).put(lessonId, 1);
        });

        // 处理收藏数据 (评分=2，如果已点赞则为3)
        favorites.forEach(favorite -> {
            Integer userId = (Integer) favorite.get("userId");
            Integer lessonId = (Integer) favorite.get("lessonId");
            
            Map<Integer, Integer> userRatings = ratings.computeIfAbsent(userId, k -> new HashMap<>());
            // 如果已经点赞，设置为3，否则为2
            int currentRating = userRatings.getOrDefault(lessonId, 0);
            userRatings.put(lessonId, currentRating == 1 ? 3 : 2);
        });

        return ratings;
    }

    /**
     * 计算用户之间的相似度
     */
    private Map<Integer, Double> calculateUserSimilarities(Integer userId, Map<Integer, Map<Integer, Integer>> userRatings) {
        Map<Integer, Integer> userLessons = userRatings.get(userId);
        Set<Integer> userLessonIds = userLessons.keySet();
        Map<Integer, Double> similarities = new HashMap<>();

        userRatings.forEach((otherUserId, otherUserLessons) -> {
            if (!otherUserId.equals(userId)) {
                // 使用Jaccard相似度计算用户相似度
                double similarity = calculateJaccardSimilarity(userLessonIds, otherUserLessons.keySet());
                if (similarity > 0) {
                    similarities.put(otherUserId, similarity);
                }
            }
        });

        return similarities;
    }

    /**
     * 使用公式Score(u,i)=Σ(Sim(u,v)× Rating(v,i))/ Σ(Sim(u,v))计算推荐分数
     */
    private Map<Integer, Double> calculateCourseScores(
            Integer userId, 
            Map<Integer, Map<Integer, Integer>> userRatings, 
            Map<Integer, Double> userSimilarities) {
        
        Map<Integer, Double> scores = new HashMap<>();
        Map<Integer, Double> simSums = new HashMap<>(); // 存储每个课程的相似度总和
        
        // 获取当前用户已评分的课程
        Set<Integer> userRatedLessons = userRatings.get(userId).keySet();
        
        // 遍历所有相似用户
        userSimilarities.forEach((similarUserId, similarity) -> {
            // 获取相似用户的评分
            Map<Integer, Integer> similarUserRatings = userRatings.get(similarUserId);
            
            // 遍历相似用户评分过的所有课程
            similarUserRatings.forEach((lessonId, rating) -> {
                // 只处理当前用户未评分的课程
                if (!userRatedLessons.contains(lessonId)) {
                    // 累加加权评分
                    double weightedRating = similarity * rating;
                    scores.put(lessonId, scores.getOrDefault(lessonId, 0.0) + weightedRating);
                    
                    // 累加相似度
                    simSums.put(lessonId, simSums.getOrDefault(lessonId, 0.0) + similarity);
                }
            });
        });
        
        // 计算最终得分 = 加权评分和 / 相似度和
        Map<Integer, Double> finalScores = new HashMap<>();
        scores.forEach((lessonId, score) -> {
            double simSum = simSums.get(lessonId);
            if (simSum > 0) {
                finalScores.put(lessonId, score / simSum);
            }
        });
        
        return finalScores;
    }

    private double calculateJaccardSimilarity(Set<Integer> set1, Set<Integer> set2) {
        Set<Integer> intersection = new HashSet<>(set1);
        intersection.retainAll(set2);

        Set<Integer> union = new HashSet<>(set1);
        union.addAll(set2);

        return union.isEmpty() ? 0 : (double) intersection.size() / union.size();
    }
} 